package service

import (
	"ddnser/common/logger"
	"ddnser/utils/errcode"
	"net"
	"strings"

	"go.uber.org/zap"
)

type MonitorService interface {
	Monitor(string, string) ([]net.IP, errcode.ErrCode)
}

type IpMonService struct {
	logger *zap.SugaredLogger
}

func NewIpMonService() *IpMonService {
	return &IpMonService{logger: logger.GetLogger()}
}

func (mon *IpMonService) Monitor(use, para string) (ips []net.IP, code errcode.ErrCode) {
	targetInterface, code := mon.SelectInt(use, para)
	if code != errcode.OK {
		return
	}
	return mon.GetUniCastIP(targetInterface)
}

func (mon *IpMonService) SelectInt(use, para string) (targetInterface *net.Interface, code errcode.ErrCode) {
	candidates, err := net.Interfaces()
	if err != nil {
		code = errcode.MONITOR_INTERFACE_ERR
		mon.logger.Errorf("mon.SelectInt: [%d]-net.Interfaces err: %s", code, err)
		return nil, code
	}
	switch strings.ToLower(use) {
	case "name":
		for _, c := range candidates {
			if c.Name == para {
				targetInterface = &c
				break
			}
		}
	case "mac":
		for _, c := range candidates {
			mac := c.HardwareAddr.String()
			hwAdds, err := net.ParseMAC(para)
			if err != nil {
				code = errcode.MONITOR_PARSE_MAC_ERR
				mon.logger.Errorf("mon.SelectInt: [%d]-net.ParseMAC err: %s", code, err)
				return nil, code
			}
			if hwAdds.String() == mac {
				targetInterface = &c
				break
			}
		}
	default:
		code = errcode.NOT_ACCEPTABLE_PARA
		return
	}
	code = errcode.OK
	mon.logger.Infof("mon.SelectInt: [%d]-%s", code, errcode.GetCodeMsg(code))
	return
}

// GetUniCastIP 获取公网地址，含v4和v6
func (mon *IpMonService) GetUniCastIP(netInterface *net.Interface) (ips []net.IP, code errcode.ErrCode) {
	addrs, err := netInterface.Addrs()
	if err != nil {
		return nil, errcode.MONITOR_GET_IP_ERR
	}
	for _, add := range addrs {
		ipnet, ok := add.(*net.IPNet)
		ip := ipnet.IP
		if !ok {
			continue
		}
		// 过滤非单播地址
		if !ip.IsGlobalUnicast() {
			continue
		}
		// 过滤私网地址
		if ip.IsPrivate() {
			continue
		}
		ips = append(ips, ip)
	}
	code = errcode.OK
	mon.logger.Infof("mon.GetUniCastIP: [%d]-%s", code, errcode.GetCodeMsg(code))
	return
}
